<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class AppLoader extends CI_Loader {

    function AppLoader(){    
        parent::CI_Loader();
        log_message('debug', "AppLoader Class Initialized");
    }
    
    function model_factory($model, $init = ''){
        if ($model == '' || is_array($model)){
            return;
        }
    
        // Is the model in a sub-folder? If so, parse out the filename and path.
        if (strpos($model, '/') === FALSE){
            $path = '';
        }else{
            $x = explode('/', $model);
            $model = end($x);            
            unset($x[count($x)-1]);
            $path = implode('/', $x).'/';
        }

        $model = strtolower($model);
        
        if ( ! file_exists(APPPATH.'models/'.$path.$model.EXT)){
            show_error('Unable to locate the model you have specified: '.$model);
        }
    
        if ( ! class_exists('Model')){
            load_class('Model', FALSE);
        }

        require_once(APPPATH.'models/'.$path.$model.EXT);

        $model = ucfirst($model);

        return new $model($init);
    }
    
    // --------------------------------------------------------------------
    
    /**
     * Module's Model Loader
     *
     * This function lets users load and instantiate a module's models.
     *
     * @access    public
     * @param    string    the name of the class
     * @param    string    name for the model
     * @param    bool    database connection
     * @return    void
     */    
    function module_model($model, $name = '', $db_conn = FALSE){
        if ($model == '' || is_array($model)){
            return;
        }

        $arr = $this->_include_path($model);
        $module_name = $arr[0];
        $model = strtolower($arr[1]);
        
        if ($name == ''){
            $name = $model;
        }
        
        if (in_array($name, $this->_ci_models, TRUE)){
            return;
        }
        
        $CI =& get_instance();
        if (isset($CI->$name)){
            show_error('The model name you are loading is the name of a resource that is already being used: '.$name);
        }
    
        $model = strtolower($model);

        if ( ! file_exists(MODPATH.$module_name.'/models/'.$model.EXT)){
            show_error('Unable to locate the model you have specified: '.$model);
        }
                
        if ($db_conn !== FALSE AND ! class_exists('CI_DB')){
            if ($db_conn === TRUE)
                $db_conn = '';
        
            $CI->load->database($db_conn, FALSE, TRUE);
        }
    
        if ( ! class_exists('Model')){
            load_class('Model', FALSE);
        }

        require_once(MODPATH.$module_name.'/models/'.$model.EXT);

        $model = ucfirst($model);

        $CI->$name = new $model();
        $CI->$name->_assign_libraries();
        
        $this->_ci_models[] = $name;    
    }

    function module_model_factory($model, $init = ''){
        if ($model == '' || is_array($model)){
            return;
        }

        $arr = $this->_include_path($model);
        $module_name = $arr[0];
        $model = strtolower($arr[1]);
        
        if ( ! file_exists(MODPATH.$module_name.'/models/'.$model.EXT)){
            show_error('Unable to locate the model you have specified: '.$model);
        }
    
        if ( ! class_exists('Model')){
            load_class('Model', FALSE);
        }

        require_once(MODPATH.$module_name.'/models/'.$model.EXT);

        $model = ucfirst($model);

        return new $model($init);
    }
    
    function module_config($file = '', $use_sections = FALSE, $fail_gracefully = FALSE){            
        $CI =& get_instance();
        $CI->config->load($file, $use_sections, $fail_gracefully);
    }
    
    function module_view($view, $vars = array(), $return = FALSE){
        return $this->_module_load(array('_ci_view' => $view, '_ci_vars' => $this->_ci_object_to_array($vars), '_ci_return' => $return));
    }
    
    function layout($view, $vars = array(), $return = FALSE){
        $_ci_data = array('_ci_view' => $view, '_ci_vars' => $this->_ci_object_to_array($vars), '_ci_return' => $return);
        // Set the default data variables
        foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return') as $_ci_val){
            $$_ci_val = ( ! isset($_ci_data[$_ci_val])) ? FALSE : $_ci_data[$_ci_val];
        }

        $tmp = explode('/', $_ci_view);
        $tmp[count($tmp)] = $tmp[count($tmp)-1];
        $tmp[count($tmp)-2] = 'views';

        $_ci_view = implode('/', $tmp);
        // Set the path to the requested file
        if ($_ci_path == ''){
            $_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION);
            
            $_ci_file = ($_ci_ext == '') ? $_ci_view.EXT : $_ci_view;
            $_ci_path = $_ci_file;
        }else{
            $_ci_x = explode('/', $_ci_path);
            $_ci_file = end($_ci_x);
        }

        if ( ! file_exists($_ci_path)){
            show_error('Unable to load the requested file: '.$_ci_file);
        }
    
        // This allows anything loaded using $this->load (views, files, etc.)
        // to become accessible from within the Controller and Model functions.
        // Only needed when running PHP 5
        
        if ($this->_ci_is_instance()){
            $_ci_CI =& get_instance();
            foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var){
                if ( ! isset($this->$_ci_key)){
                    $this->$_ci_key =& $_ci_CI->$_ci_key;
                }
            }
        }

        /*
         * Extract and cache variables
         *
         * You can either set variables using the dedicated $this->load_vars()
         * function or via the second parameter of this function. We'll merge
         * the two types and cache them so that views that are embedded within
         * other views can have access to these variables.
         */    
        if (is_array($_ci_vars)){
            $this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars);
        }
        extract($this->_ci_cached_vars);
                
        /*
         * Buffer the output
         *
         * We buffer the output for two reasons:
         * 1. Speed. You get a significant speed boost.
         * 2. So that the final rendered template can be
         * post-processed by the output class.  Why do we
         * need post processing?  For one thing, in order to
         * show the elapsed page load time.  Unless we
         * can intercept the content right before it's sent to
         * the browser and then stop the timer it won't be accurate.
         */
        ob_start();
                
        // If the PHP installation does not support short tags we'll
        // do a little string replacement, changing the short tags
        // to standard PHP echo statements.
        
        if ((bool) @ini_get('short_open_tag') === FALSE AND config_item('rewrite_short_tags') == TRUE){
            echo eval('?>'.preg_replace("/;*\s*\?>/", "; ?>", str_replace('<?=', '<?php echo ', file_get_contents($_ci_path))));
        }else{
            include($_ci_path); // include() vs include_once() allows for multiple views with the same name
        }
        
        log_message('debug', 'File loaded: '.$_ci_path);
        
        // Return the file data if requested
        if ($_ci_return === TRUE){        
            $buffer = ob_get_contents();
            @ob_end_clean();
            return $buffer;
        }

        /*
         * Flush the buffer... or buff the flusher?
         *
         * In order to permit views to be nested within
         * other views, we need to flush the content back out whenever
         * we are beyond the first level of output buffering so that
         * it can be seen and included properly by the first included
         * template and any subsequent ones. Oy!
         *
         */    
        if (ob_get_level() > $this->_ci_ob_level + 1){
            ob_end_flush();
        }else{
            // PHP 4 requires that we use a global
            global $OUT;
            $OUT->append_output(ob_get_contents());
            @ob_end_clean();
        }
    }
    
    function module_define($module){
        $arr = $this->_include_path($module);
        $module_name = $arr[0];
        require_once MODPATH.$module_name.'/config/defines.php';
    }
    
    function module_library($library = '', $params = NULL, $object_name = NULL)
    {
        if ($library == ''){
            return FALSE;
        }

        if ( ! is_null($params) AND ! is_array($params)){
            $params = NULL;
        }

        if (is_array($library)){
            foreach ($library as $class){
                $this->_module_load_class($class, $params, $object_name);
            }
        }else{
            $this->_module_load_class($library, $params, $object_name);
        }
        
        $this->_ci_assign_to_models();
    }

    function module_language($file = array(), $lang = ''){
        $CI =& get_instance();

        if ( ! is_array($file)){
            $file = array($file);
        }

        foreach ($file as $langfile){    
            $CI->lang->module_load($langfile, $lang);
        }
    }
    
    function module_helper($helpers = array()){
        if ( ! is_array($helpers)){
            $helpers = array($helpers);
        }
    
        foreach ($helpers as $helper){
            $arr = $this->_include_path($helper);
            $module_name = $arr[0];
            $helper = $arr[1];
            $helper = strtolower(str_replace(EXT, '', str_replace('_helper', '', $helper)).'_helper');

            if (isset($this->_ci_helpers[$helper])){
                continue;
            }

            if (file_exists(MODPATH.$module_name.'/helpers/'.$helper.EXT)){
                include_once(MODPATH.$module_name.'/helpers/'.$helper.EXT);
            }else{
                show_error('Unable to load the requested file: helpers/'.$helper.EXT);
            }

            $this->_ci_helpers[$helper] = TRUE;
            log_message('debug', 'Helper loaded: '.$helper);    
        }        
    }
    
    function _include_path($model){
        $arr = Modules::search_path($model);
        $arr[0] = $arr[3].'/'.$arr[0];
        return $arr;
    }
    
    function _module_load($_ci_data){
        // Set the default data variables
        foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return') as $_ci_val){
            $$_ci_val = ( ! isset($_ci_data[$_ci_val])) ? FALSE : $_ci_data[$_ci_val];
        }

        $arr = $this->_include_path($_ci_view);
        $module_name = $arr[0];
        $_ci_view = strtolower($arr[1]);
        
        // Set the path to the requested file
        if ($_ci_path == ''){
            $_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION);
            $_ci_file = ($_ci_ext == '') ? $_ci_view.EXT : $_ci_view;
            $_ci_path = MODPATH.$module_name.'/views/'.$_ci_file;
        }else{
            $_ci_x = explode('/', $_ci_path);
            $_ci_file = end($_ci_x);
        }
        
        if ( ! file_exists($_ci_path)){
            show_error('Unable to load the requested file: '.$_ci_file);
        }
    
        // This allows anything loaded using $this->load (views, files, etc.)
        // to become accessible from within the Controller and Model functions.
        // Only needed when running PHP 5
        
        if ($this->_ci_is_instance()){
            $_ci_CI =& get_instance();
            foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var){
                if ( ! isset($this->$_ci_key)){
                    $this->$_ci_key =& $_ci_CI->$_ci_key;
                }
            }
        }

        /*
         * Extract and cache variables
         *
         * You can either set variables using the dedicated $this->load_vars()
         * function or via the second parameter of this function. We'll merge
         * the two types and cache them so that views that are embedded within
         * other views can have access to these variables.
         */    
        if (is_array($_ci_vars)){
            $this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars);
        }
        extract($this->_ci_cached_vars);
                
        /*
         * Buffer the output
         *
         * We buffer the output for two reasons:
         * 1. Speed. You get a significant speed boost.
         * 2. So that the final rendered template can be
         * post-processed by the output class.  Why do we
         * need post processing?  For one thing, in order to
         * show the elapsed page load time.  Unless we
         * can intercept the content right before it's sent to
         * the browser and then stop the timer it won't be accurate.
         */
        ob_start();
                
        // If the PHP installation does not support short tags we'll
        // do a little string replacement, changing the short tags
        // to standard PHP echo statements.
        
        if ((bool) @ini_get('short_open_tag') === FALSE AND config_item('rewrite_short_tags') == TRUE){
            echo eval('?>'.preg_replace("/;*\s*\?>/", "; ?>", str_replace('<?=', '<?php echo ', file_get_contents($_ci_path))));
        }else{
            include($_ci_path); // include() vs include_once() allows for multiple views with the same name
        }
        
        log_message('debug', 'File loaded: '.$_ci_path);
        
        // Return the file data if requested
        if ($_ci_return === TRUE){        
            $buffer = ob_get_contents();
            @ob_end_clean();
            return $buffer;
        }

        /*
         * Flush the buffer... or buff the flusher?
         *
         * In order to permit views to be nested within
         * other views, we need to flush the content back out whenever
         * we are beyond the first level of output buffering so that
         * it can be seen and included properly by the first included
         * template and any subsequent ones. Oy!
         *
         */    
        if (ob_get_level() > $this->_ci_ob_level + 1){
            ob_end_flush();
        }else{
            // PHP 4 requires that we use a global
            global $OUT;
            $OUT->append_output(ob_get_contents());
            @ob_end_clean();
        }
    }
    // --------------------------------------------------------------------
    function _module_load_class($class, $params = NULL, $object_name = NULL){
        // Get the class name, and while we're at it trim any slashes.  
        // The directory path can be included as part of the class name, 
        // but we don't want a leading slash
        $class = str_replace(EXT, '', trim($class, '/'));

        $arr = $this->_include_path($class);
        $module_name = $arr[0];
        $class = $arr[1];

        // We'll test for both lowercase and capitalized versions of the file name
        foreach (array(ucfirst($class), strtolower($class)) as $class){
            // Lets search for the requested library file and load it.
            $is_duplicate = FALSE;        

                $path = MODPATH.$module_name;
                $filepath = $path.'/libraries/'.$class.EXT;
                
                // Does the file exist?  No?  Bummer...
                if ( ! file_exists($filepath)){
                    continue;
                }
                
                // Safety:  Was the class already loaded by a previous call?
                if (in_array($filepath, $this->_ci_loaded_files)){
                    // Before we deem this to be a duplicate request, let's see
                    // if a custom object name is being supplied.  If so, we'll
                    // return a new instance of the object
                    if ( ! is_null($object_name)){
                        $CI =& get_instance();
                        if ( ! isset($CI->$object_name)){
                            return $this->_ci_init_class($class, '', $params, $object_name);
                        }
                    }
                
                    $is_duplicate = TRUE;
                    log_message('debug', $class." class already loaded. Second attempt ignored.");
                    return;
                }
                
                include_once($filepath);
                $this->_ci_loaded_files[] = $filepath;
                return $this->_ci_init_class($class, '', $params, $object_name);

        } // END FOREACH

        
        // If we got this far we were unable to find the requested class.
        // We do not issue errors if the load call failed due to a duplicate request
        if ($is_duplicate == FALSE){
            log_message('error', "Unable to load the requested class: ".$class);
            show_error("Unable to load the requested class: ".$class);
        }
    }
    
    // --------------------------------------------------------------------
	
	/**
	 * Autoloader
	 *
	 * The config/autoload.php file contains an array that permits sub-systems,
	 * libraries, plugins, and helpers to be loaded automatically.
	 *
	 * @access	private
	 * @param	array
	 * @return	void
        * Override parent autoloader by Luan Nguyen
	 */
	function _ci_autoloader()
	{
        $d = dir(APPPATH.'config/db_define');

        while (false !== ($entry = $d->read())) {
            if($entry != '.' && $entry != '..' && stripos($entry, EXT)!==FALSE){
                include_once(APPPATH.'config/db_define/'.$entry);
            }
        }
        $d->close();

		include_once(APPPATH.'config/autoload'.EXT);
		
		if ( ! isset($autoload))
		{
			return FALSE;
		}
		
		// Load any custom config file
		if (count($autoload['config']) > 0)
		{			
			$CI =& get_instance();
			foreach ($autoload['config'] as $key => $val)
			{
				$CI->config->load($val);
			}
		}		

		// Autoload plugins, helpers and languages
		foreach (array('helper', 'plugin', 'language') as $type)
		{			
			if (isset($autoload[$type]) AND count($autoload[$type]) > 0)
			{
				$this->$type($autoload[$type]);
			}		
		}

		// A little tweak to remain backward compatible
		// The $autoload['core'] item was deprecated
		if ( ! isset($autoload['libraries']))
		{
			$autoload['libraries'] = $autoload['core'];
		}
		
		// Load libraries
		if (isset($autoload['libraries']) AND count($autoload['libraries']) > 0)
		{
			// Load the database driver.
			if (in_array('database', $autoload['libraries']))
			{
				$this->database();
				$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));
			}

			// Load scaffolding
			if (in_array('scaffolding', $autoload['libraries']))
			{
				$this->scaffolding();
				$autoload['libraries'] = array_diff($autoload['libraries'], array('scaffolding'));
			}
		
			// Load all other libraries
			foreach ($autoload['libraries'] as $item)
			{
				$this->library($item);
			}
		}		

		// Autoload models
		if (isset($autoload['model']))
		{
			$this->model($autoload['model']);
		}

	}
}
/* End of file Loader.php */
/* Location: ./system/libraries/Loader.php */